﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Threading;

using ZetaPrints.ZetaClient.Data;
using ZetaPrints.ZetaClient.Data.Repository.Linq;
using ZetaPrints.ZetaClient.Shared;
using ZetaPrints.ZetaClient.Business.ThreadSubSytem;

namespace ZetaPrints.ZetaClient.Business
{
    [DebuggerDisplay("{OrderEntry.OrderId}")]
    public class OrderManager:BaseManager
    {
        #region public properties
        /// <summary>
        /// The data for this entry
        /// </summary>
        public Order OrderEntry { get; set; } 
        /// <summary>
        /// List of files within this order
        /// </summary>
        public List<FileManager> FileManagerList{get;set;}
        /// <summary>
        /// Gets if we have already downloaded the detail
        /// for this entry
        /// </summary>
        public bool HasDetails
        {
            get
            {
                bool haveDetails = false;

                /// first check to make sure we are not null
                if (
                    (OrderEntry.XmlOrderDetail != null) ||
                    (OrderEntry.XmlUserDetail != null) ||
                    (OrderEntry.OrderCommentDetail.Count != 0) ||
                    (OrderEntry.OrderFieldDetail.Count != 0) ||
                    (OrderEntry.OrderFileDetail.Count != 0) ||
                    (OrderEntry.OrderFontDetail.Count != 0)
                    )
                {
                    haveDetails = true;
                }

                return haveDetails;
            }
        }
        /// <summary>
        /// If we have records of files
        /// </summary>
        public bool HasFileRecords
        {
            get
            {
                bool hasFileRecords = false;

                if (FileManagerList != null)
                {
                    if (FileManagerList.Count > 0)
                    {
                        hasFileRecords = true;
                    }
                }

                return hasFileRecords;
            }
        }
        /// <summary>
        /// Have we downloaded all the files for this order?
        /// </summary>
        public bool HasLocalFiles
        {
            get
            {
                bool hasFiles = false;

                if (FileManagerList != null)
                {
                    foreach (FileManager fileManager in FileManagerList)
                    {
                        if (fileManager.FileExistsLocaly)
                        {
                            hasFiles = true;
                            break;
                        }
                    }
                }

                return hasFiles;
            }
        }
        /// <summary>
        /// Do we have any threads on this system running
        /// </summary>
        /// <returns></returns>
        public override bool AreThreadsAlive
        {
            get
            {
                bool threadsAreAlive = false;

                threadsAreAlive = ThreadManager.AreThreadsAlive;

                /// if we did not get a true, try the sub levels
                if (!threadsAreAlive)
                {
                    foreach (FileManager fileManager in FileManagerList)
                    {
                        /// is this entry running?
                        if (fileManager.ThreadManager.AreThreadsAlive)
                        {
                            /// found an running entry. Get out, got
                            /// our answer
                            threadsAreAlive = true;
                            break;
                        }
                    }
                }

                return ThreadManager.AreThreadsAlive;
            }
        }
        #endregion


        #region constructors
        /// <summary>
        /// Initializes the order manager with an order
        /// </summary>
        /// <param name="order"></param>
        public OrderManager(Site site, Order order)
            : base(site)
        {
            Initialize(order);
        }
        /// <summary>
        /// Initializes the OrderManager with a 
        /// order guid
        /// </summary>
        /// <param name="orderId"></param>
        public OrderManager(Site site, Guid orderId)
            : base(site)
        {
            Initialize(_dataRepositoryManager.FetchOrder(orderId));
        }
        /// <summary>
        /// Initializes the order manager with an order
        /// </summary>
        /// <param name="order"></param>
        public OrderManager(string siteName, Order order)
            : base(siteName)
        {
            Initialize(order);
        }
        /// <summary>
        /// Initializes the OrderManager with a 
        /// order guid
        /// </summary>
        /// <param name="orderId"></param>
        public OrderManager(string siteName, Guid orderId)
            : base(siteName)
        {
            Initialize(_dataRepositoryManager.FetchOrder(orderId));
        }
        #endregion


        #region private methods
        /// <summary>
        /// Initializes the class
        /// </summary>
        /// <param name="orderEntry"></param>
        private void Initialize(Order orderEntry)
        {
            OrderEntry = orderEntry;
            FileManagerList = new List<FileManager>();
        }
        /// <summary>
        /// Refreshes the current order entry with the one from the DB
        /// </summary>
        private void RefreshOrderEntry()
        {
            OrderEntry = _dataRepositoryManager.FetchOrder(OrderEntry.OrderId);
        }
        #region order detail
        /// <summary>
        /// Gets the order detail from the web site and saves it
        /// </summary>
        /// <param name="orderId"></param>
        private void DownloadOrderDetailsThread(object forceDownloadAllAtachmentsObject)
        {
            bool forceDownloadAllAtachments = (bool)forceDownloadAllAtachmentsObject;

            ZetaClientConfiguration zetaClientConfiguration = new ZetaClientConfiguration();

            if (_webAction.GetOrderDetail(OrderEntry.OrderId))
            {
                ParseXml(XElement.Parse(_webAction.Data));

                if ((zetaClientConfiguration.DownloadFiles) || (forceDownloadAllAtachments))
                {
                    /// go through each order file and create and download them
                    foreach( OrderFileDetail orderFileDetail in OrderEntry.OrderFileDetail)
                    {
                        FileManager fileManager = new FileManager(SiteEntry, orderFileDetail);
                        fileManager.OnEventMessenger +=new EventHandler<EventMessenger>(base_OnEventMessenger);
                        fileManager.DownloadFile(forceDownloadAllAtachments);
                    }
                }
            }

            SendMessage(MessageTypeOption.DownloadOrderDetailsThread, OrderEntry.OrderId.ToString());
        }
        /// <summary>
        /// The thread to run when we are doing a web request to change our status
        /// </summary>
        /// <param name="newStatusObject"></param>
        private void ChangeOrderStatusThread(object newStatusObject)
        {
            string newStatus = (string)newStatusObject;

            if (_webAction.SetStatus(OrderEntry.OrderId, newStatus, OrderEntry.OrderStatus.OrderStatusName))
            {
                ParseXml(XElement.Parse(_webAction.Data));
            }

            SendMessage(MessageTypeOption.ChangeOrderStatusThread, OrderEntry.OrderId.ToString());
        }
        #endregion
        #region file
        /// <summary>
        /// Fetches all the order from the database
        /// </summary>
        private void FetchOrderFileDetailThread()
        {
            SendMessage(MessageTypeOption.Message, "Fetching file detail information");

            bool fetchInfo = true;

            if ((FileManagerList != null) && (OrderEntry.OrderFileDetail != null))
            {
                /// if they are not the same it means it is not fetched.
                if (OrderEntry.OrderFileDetail.Count() == FileManagerList.Count)
                {
                    fetchInfo = false;
                }
            }

            if (fetchInfo)
            {
                List<OrderFileDetail> orderFileDetailList = _dataRepositoryManager.FetchOrderFileDetailList(OrderEntry.OrderId);

                foreach (OrderFileDetail orderFileDetail in orderFileDetailList)
                {
                    AddFileManager(new FileManager(SiteEntry, orderFileDetail));
                }
            }

            /// list of entry ready
            SendMessage(MessageTypeOption.FetchOrderFileDetailThread, OrderEntry.OrderId.ToString());
        }
        /// <summary>
        /// Adds a file manager to the list
        /// </summary>
        /// <param name="fileManager"></param>
        private void AddFileManager(FileManager fileManager)
        {
            bool duplicateFound = false;
            fileManager.OnEventMessenger += new EventHandler<EventMessenger>(base_OnEventMessenger);

            /// og looking for a duplicate entry
            for( int count = 0; count < FileManagerList.Count; count++)
            {
                if( FileManagerList[count].OrderFileDetailEntry.FileIndex == fileManager.OrderFileDetailEntry.FileIndex )
                {
                     FileManagerList[count].AbortAllThreads();
                    FileManagerList[count] = fileManager;
                }
            }

            /// no duplicate go ahead and just add it
            if (!duplicateFound)
            {
                FileManagerList.Add(fileManager);
            }
        }
        #endregion
        #endregion


        #region public methods
        #region xml
        /// <summary>
        /// Saves order and order details from the website using XML
        /// </summary>
        /// <param name="xOrderOrderDetail"></param>
        public override void ParseXml(XElement xOrderDetail)
        {
            bool refreshOrderEntry = false;

            if (xOrderDetail.Name.ToString() == XmlNameOption.Order.ToString())
            {
                refreshOrderEntry = _dataRepositoryManager.SaveOrderList(OrderEntry.SiteId, xOrderDetail);
            }
            else if (xOrderDetail.Name.ToString() == XmlNameOption.OrderDetails.ToString())
            {
                refreshOrderEntry = _dataRepositoryManager.SaveOrderDetail(SiteEntry.SiteId, xOrderDetail);
            }

            if (refreshOrderEntry)
            {
                RefreshOrderEntry();
            }
        }
        /// <summary>
        /// Gets the xml for Order
        /// </summary>
        /// <returns></returns>
        public override XElement ToXml()
        {
            XElement xOrder = new XElement("Order");

            if (OrderEntry != null)
            {
                if (OrderEntry.XmlOrderDetail != null)
                {
                    xOrder.Add(XElement.Parse(OrderEntry.XmlOrderDetail));
                }

                if (OrderEntry.XmlUserDetail != null)
                {
                    xOrder.Add(XElement.Parse(OrderEntry.XmlUserDetail));
                }

                foreach (OrderCommentDetail orderCommentDetail in OrderEntry.OrderCommentDetail)
                {
                    xOrder.Add(XElement.Parse(orderCommentDetail.Xml));
                }

                foreach (OrderFieldDetail orderFieldDetail in OrderEntry.OrderFieldDetail)
                {
                    xOrder.Add(XElement.Parse(orderFieldDetail.Xml));
                }

                foreach (OrderFontDetail orderFontDetail in OrderEntry.OrderFontDetail)
                {
                    xOrder.Add(XElement.Parse(orderFontDetail.Xml));
                }

                foreach (OrderFileDetail orderFileDetail in OrderEntry.OrderFileDetail)
                {
                    xOrder.Add(XElement.Parse(orderFileDetail.Xml));
                }

                if (OrderEntry.OrderPayPalDetail.Count() > 0)
                {
                    xOrder.Add(XElement.Parse(OrderEntry.OrderPayPalDetail.First().Xml));
                }
            }

            return xOrder;
        }
        #endregion
        #region file
        /// <summary>
        /// Gets a file manager that has already been fetched and
        /// downloaded to the system.
        /// </summary>
        /// <param name="fileIndex"></param>
        /// <returns></returns>
        public FileManager GetFileManager(int fileIndex)
        {
            FileManager fileManager = null;

            var fileManagerData = (from fileManagerItem in FileManagerList
                                   where fileManagerItem.OrderFileDetailEntry.FileIndex == fileIndex
                                   select fileManagerItem).Take(1);

            if (fileManagerData.Count() > 0)
            {
                fileManager = fileManagerData.First();
            }

            return fileManager;
        }
        /// <summary>
        /// Gets the file manager list for this order
        /// </summary>
        /// <returns></returns>
        public void FetchFileList()
        {
            Thread thread = new Thread(new ThreadStart(FetchOrderFileDetailThread));

            ThreadManager.AddThread(OrderEntry.OrderId, ThreadActionOption.FetchFiles, thread);
        }
        /// <summary>
        /// Changes the order status of this order on the web
        /// </summary>
        /// <param name="newOrderStatus"></param>
        public void SetOrderStatus(string newOrderStatus)
        {
            Thread thread = new Thread(new ParameterizedThreadStart(ChangeOrderStatusThread));

            ThreadManager.AddThread(OrderEntry.OrderId, ThreadActionOption.FetchFiles, thread, newOrderStatus);
        }
        /// <summary>
        /// Goes through all the orderfile details and find
        /// if a all files were not downloaded, or a file is not
        /// where it should be.
        /// </summary>
        /// <returns></returns>
        public bool AreFilesMissingOnOrder()
        {
            bool filesMissing = true;

            if (OrderEntry != null)
            {
                foreach (OrderFileDetail orderFile in OrderEntry.OrderFileDetail)
                {
                    if (orderFile.LocalPath != null)
                    {
                        /// we have a file that was not
                        /// downloaded
                        filesMissing = false;
                        break;
                    }
                    else
                    {
                        if (System.IO.File.Exists(orderFile.LocalPath))
                        {
                            /// the file is on the local path, but does
                            /// not exist
                            filesMissing = false;
                            break;
                        }
                    }
                }
            }

            return filesMissing;
        }
        /// <summary>
        /// Forces the system to download the file no mater what
        /// </summary>
        /// <param name="forceDownload"></param>
        public void DownloadFileDetails(bool forceDownload)
        {
            if (FileManagerList != null)
            {
                foreach (FileManager fileManager in FileManagerList)
                {
                    fileManager.DownloadFile(forceDownload);
                }
            }
        }
        /// <summary>
        /// Moves a file
        /// </summary>
        /// <param name="fileIndex"></param>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        public bool MoveFile(int fileIndex, string source, string destination)
        {
            bool moveFileSuccess = false;

            var fileManager = from fileManagerData in FileManagerList
                              where fileManagerData.OrderFileDetailEntry.FileIndex == fileIndex
                              select fileManagerData;

            if (fileManager.Count() > 0)
            {
                moveFileSuccess = fileManager.First().MoveFile(source, destination);
            }

            return moveFileSuccess;
        }
        #endregion
        #region order details
        /// <summary>
        /// Downloads and saves all the details
        /// </summary>
        /// <param name="forceDownloadAllAtachments"></param>
        public void DownloadOrderDetails(bool forceDownloadAllAtachments)
        {
            Thread thread = new Thread(new ParameterizedThreadStart(DownloadOrderDetailsThread));

            ThreadManager.AddThread(OrderEntry.OrderId, ThreadActionOption.DownloadOrderDetails, thread, forceDownloadAllAtachments);
        }
        #endregion
        #endregion
    }
}
